package com.evil.activiti.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import com.alibaba.fastjson.JSON;
import com.evil.activiti.util.ActivityUtil;
import com.evil.application.api.RemoteApplicationOrderLogService;
import com.evil.application.api.RemoteApplicationOrderNodeService;
import com.evil.application.enums.order.OrderSpecialControlEnum;
import com.evil.application.enums.process.CompleteTypeEnum;
import com.evil.application.pojo.dto.order.log.AddRobotLogReqDTO;
import com.evil.application.pojo.dto.order.node.HandleOrderNodeReqDTO;
import com.evil.application.pojo.dto.order.node.ModifyOrderNodeDataReqDTO;
import com.evil.common.account.dto.user.UserEnterpriseBaseDTO;
import com.evil.common.activiti.enums.HandleTypeEnum;
import com.evil.common.activiti.enums.NodeTypeEnum;
import com.evil.common.family.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.impl.persistence.entity.VariableInstance;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 流程流转监听器
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@Component("TaskCompleteListener")
@AllArgsConstructor
public class TaskCompleteListener implements ExecutionListener {

    private final RemoteApplicationOrderLogService remoteApplicationOrderLogService;

    private final RemoteApplicationOrderNodeService remoteApplicationOrderNodeService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void notify(DelegateExecution execution) {
        String eventName = execution.getEventName();
        Long orderId = execution.getVariable(ActivityUtil.getProcessOrderIdKey(), Long.class);
        FlowElement flowElement = execution.getCurrentFlowElement();
        Map<String, Object> variables = execution.getVariables();
        log.info("【流程流转监听器】，execution.getEventName参数：{}", eventName);
        log.info("【流程流转监听器】，订单id:{}", orderId);
        log.info("【流程流转监听器】，节点id：{}, 节点name:{}", flowElement.getId(), flowElement.getName());
        log.info("【流程流转监听器】，execution.getVariables参数：{}", JSON.toJSONString(variables));

        if (EVENTNAME_END.equals(eventName)) {
            execution.setVariableLocal(ActivityUtil.ASSIGNED_LIST, new ArrayList<>());

            // 节点流转
            String remark = execution.getVariable(ActivityUtil.REMARK, String.class);
            Long nodeId = ActivityUtil.restoreFlowNodeId(flowElement.getId());
            NodeTypeEnum nodeTypeEnum = ActivityUtil.restoreFlowNodeTypeEnum(flowElement.getId());
            if (flowElement instanceof StartEvent) {
                // 开始节点
                Long creatorControlId = OrderSpecialControlEnum.CREATOR.getId();
                String processCompleteKey = ActivityUtil.getProcessCompleteKey(creatorControlId);
                List<Long> dataValues = ActivityUtil.getListForVariables(execution.getVariables(), processCompleteKey, Long.class);
                if (CollectionUtil.isEmpty(dataValues)) {
                    throw new BusinessException(RCodeEnum.ACTIVITY_COMPLETE_ERROR);
                }

                // 订单节点流转
                HandleOrderNodeReqDTO handleOrderNodeReqDTO = new HandleOrderNodeReqDTO();
                handleOrderNodeReqDTO.setOrderId(orderId);
                handleOrderNodeReqDTO.setNodeId(nodeId);
                handleOrderNodeReqDTO.setHandlerId(dataValues.get(0));
                handleOrderNodeReqDTO.setHandleType(HandleTypeEnum.START.getId());
                handleOrderNodeReqDTO.setRemark(remark);
                remoteApplicationOrderNodeService.handleOrderNode(handleOrderNodeReqDTO);
            } else if (flowElement instanceof UserTask) {
                UserTask userTask = (UserTask) flowElement;
                // 目前 出口线永远只有一条
                SequenceFlow sequenceFlow = userTask.getOutgoingFlows().stream().findFirst()
                        .orElseThrow(() -> new BusinessException(RCodeEnum.ACTIVITY_COMPLETE_ERROR));

                // 判断节点是否全部已完成，（会签）全部已完成后，会签节点的根execution 会再进来一次，这里做一下校验
                boolean completed = false;
                Boolean isCountersign = execution.getVariableLocal(ActivityUtil.IS_COUNTERSIGN, Boolean.class);
                if (BooleanUtil.isTrue(isCountersign)) {
                    // 是会签
                    VariableInstance nrOfActiveInstances = execution.getVariableInstance(ActivityUtil.nrOfActiveInstances);
                    if (null != nrOfActiveInstances && null != nrOfActiveInstances.getLongValue()) {
                        // 会签已完成
                        completed = nrOfActiveInstances.getLongValue().equals(0L);
                    }
                }
                // 用户节点(除了抄送节点、回退停止、拒绝停止) -> 流转 节点日志
                if (NodeTypeEnum.CARBON_COPY_NODE.getId() != nodeTypeEnum.getId()
                        && !ActivityUtil.generateStopNodeId().equals(sequenceFlow.getTargetRef())
                        && !ActivityUtil.generateRefuseNodeId().equals(sequenceFlow.getTargetRef())
                        && !completed) {
                    UserEnterpriseBaseDTO assignee = ActivityUtil.getUserEnterpriseByActivitiLoginUser();

                    // 订单节点流转
                    HandleOrderNodeReqDTO handleOrderNodeReqDTO = new HandleOrderNodeReqDTO();
                    handleOrderNodeReqDTO.setOrderId(orderId);
                    handleOrderNodeReqDTO.setNodeId(nodeId);
                    handleOrderNodeReqDTO.setHandlerId(assignee.getUserId());
                    Integer completeType = execution.getVariable(ActivityUtil.COMPLETE_TYPE, Integer.class);
                    HandleTypeEnum handleTypeEnum = CompleteTypeEnum.isExistById(completeType).getHandleTypeEnum(nodeTypeEnum);
                    handleOrderNodeReqDTO.setHandleType(handleTypeEnum.getId());
                    handleOrderNodeReqDTO.setRemark(remark);
                    remoteApplicationOrderNodeService.handleOrderNode(handleOrderNodeReqDTO);

                    // 更新订单节点数据
                    ModifyOrderNodeDataReqDTO modifyOrderNodeDataReqDTO = new ModifyOrderNodeDataReqDTO();
                    modifyOrderNodeDataReqDTO.setOrderId(orderId);
                    modifyOrderNodeDataReqDTO.setIsOnlyModifyHandlers(true);
                    modifyOrderNodeDataReqDTO.setNodeHandlersMap(MapUtil.of(nodeId, Collections.singletonList(assignee)));
                    modifyOrderNodeDataReqDTO.setHandleType(handleTypeEnum.getId());
                    remoteApplicationOrderNodeService.modifyOrderNodeData(modifyOrderNodeDataReqDTO);
                }
            } else if (flowElement instanceof ServiceTask) {
                // 机器人节点 -> 添加 “机器人” 节点日志
                AddRobotLogReqDTO addRobotLogReqDTO = new AddRobotLogReqDTO();
                addRobotLogReqDTO.setOrderId(orderId);
                addRobotLogReqDTO.setNodeId(nodeId);
                if (NodeTypeEnum.ADD_ROBOT_NODE.getId() == nodeTypeEnum.getId()) {
                    addRobotLogReqDTO.setHandleType(HandleTypeEnum.ADD_ROBOT.getId());
                } else {
                    addRobotLogReqDTO.setHandleType(HandleTypeEnum.MODIFY_ROBOT.getId());
                }
                addRobotLogReqDTO.setRemark(remark);
                remoteApplicationOrderLogService.addOrderLog(addRobotLogReqDTO);
            }
        }
    }
}
